#include "scripting/script_parser.h"
#include <algorithm>

namespace script
{
class ScriptParserData
{
private:
    friend class ScriptParser;
    Tokens tokens;
    int position{0};//当前待处理的符号
    std::string error_message;

private:
    /**
     * @brief:  解析表达式
     * @author: sherlock_lht
     */
    std::optional<ASTNode> parseStatements();
    std::optional<ASTNode> parseStatement();

    /**
     * @brief:  解析var声明
     * @author: sherlock_lht
     */
    std::optional<ASTNode> parseVarDeclaration();

    /**
     * @brief:  解析function声明
     * @author: sherlock_lht
     */
    std::optional<ASTNode> parseFunctionDeclaration();

    /**
     * @brief:  解析if语句
     * @author: sherlock_lht
     */
    std::optional<ASTNode> parseIfStatement(const Token &token);

    /**
     * @brief:  解析表达式，包括if、while
     * @author: sherlock_lht
     */
    bool parseExpression(ASTNode &ast_node);

    /**
     * @brief:  处理表达式内部信息，区分and、or、not等
     * @author: sherlock_lht
     */
    bool parseExpressionContent(ASTNode &ast_node);

    /**
     * @brief:  处理单个and表达式，将and后面的标识符放到and子节点中
     * @author: sherlock_lht
     */
    bool parseAndExpression(ASTNode &ast_node);

    /**
     * @brief:  解析连续and表达式，把连续and，加上前面的表达式，合并成一个and
     * @author: sherlock_lht
     */
    bool parseContinueAndExpression(ASTNode &ast_node);

    /**
     * @brief:  解析连续or表达式，把连续的or，加上前面的表达式，合并成一个or
     * @author: sherlock_lht
     */
    bool parseContinueOrExpression(ASTNode &ast_node);

    /**
     * @brief:  解析not表达式，仅限被!修饰的内容
     * @author: sherlock_lht
     */
    bool parseNotExpression(ASTNode &ast_node);

    /**
     * @brief:  解析非循环执行体，执行体由{}包裹，和parseWhileExecutant的区别是，其不能有break
     * @author: sherlock_lht
     */
    bool parseNoWhileExecutant(ASTNode &ast_node);

    bool parseNoWhileExecutantDirect(ASTNode &ast_node);

    /**
    * @brief:  解析循环执行体，执行体由{}包裹
    * @author: sherlock_lht
    */
    bool parseWhileExecutant(ASTNode &ast_node);

    /**
     * @brief:  解析repeat语句
     * @author: sherlock_lht
     */
    std::optional<ASTNode> parseRepeatStatement(const Token &token);

    /**
     * @brief:  解析retry语句
     * @author: sherlock_lht
     */
    std::optional<ASTNode> parseRetryStatement(const Token &token);

    /**
     * @brief:  解析while循环
     * @author: sherlock_lht
     */
    std::optional<ASTNode> parseWhileLoop(const Token &token);

    /**
     * @brief:  解析reactive语句
     * @author: sherlock_lht
     */
    std::optional<ASTNode> parseReactiveStatement(const Token &token);

    /**
     * @brief:  解析parallel语句
     * @author: sherlock_lht
     */
    std::optional<ASTNode> parseParallelStatement(const Token &token);

    std::optional<ASTNode> parseForcePassStatement(const Token &token);

    std::optional<ASTNode> parseForceFailStatement(const Token &token);

    /**
     * @brief:  检查当前待处理的符号是否和传入的吻合
     * @note:   如果吻合，则position指向下一个待处理符号；如果不吻合，则position仍然指向当前符号
     * @author: sherlock_lht
     */
    std::optional<Token> match(TokenType token_type);
    std::optional<Token> match(TokenType token_type, const std::string &value);

    void setErrorMessage(const std::string &error_massage);
};

std::optional<ASTNode> ScriptParserData::parseStatements()
{
    ASTNode node;
    while (position < tokens.tokens.size())
    {
        std::optional<ASTNode> ast_node = parseStatement();
        if (ast_node)
        {
            node.children.push_back(std::move(ast_node.value()));
        }
        else
        {
            return std::nullopt;
        }
    }
    return node;
}
std::optional<ASTNode> ScriptParserData::parseStatement()
{
    if (match(TokenType::KeyWord, "var"))
    {
        return parseVarDeclaration();
    }
    else if (auto func_token = match(TokenType::KeyWord, "function"))
    {
        return parseFunctionDeclaration();
    }
    else if (auto if_token = match(TokenType::KeyWord, "if"))
    {
        return parseIfStatement(if_token.value());
    }
    else if (auto repeat_token = match(TokenType::KeyWord, "repeat"))
    {
        return parseRepeatStatement(repeat_token.value());
    }
    else if (auto retry_token = match(TokenType::KeyWord, "retry"))
    {
        return parseRetryStatement(retry_token.value());
    }
    else if (auto while_token = match(TokenType::KeyWord, "while"))
    {
        return parseWhileLoop(while_token.value());
    }
    else if (auto reactive_token = match(TokenType::KeyWord, "reactive"))
    {
        return parseReactiveStatement(reactive_token.value());
    }
    else if (auto parallel_token = match(TokenType::KeyWord, "parallel"))
    {
        return parseParallelStatement(parallel_token.value());
    }
    else if (auto force_pass_token = match(TokenType::KeyWord, "force_pass"))
    {
        return parseForcePassStatement(force_pass_token.value());
    }
    else if (auto force_fail_token = match(TokenType::KeyWord, "force_fail"))
    {
        return parseForceFailStatement(force_fail_token.value());
    }
    else
    {
        //可能是运行语句，非关键字开头
        if (auto identifier = match(TokenType::Identifier))
        {
            return std::make_optional<ASTNode>(ASTNodeType::Identifier, identifier->token_value, identifier.value());
        }
        //剩下的都是错误token
        error_message = "invalid statement, unexpected token";
        return std::nullopt;
    }
}
std::optional<ASTNode> ScriptParserData::parseVarDeclaration()
{
    //e.g. var get_pose = GetPose("get_pose")
    auto variable_token = match(TokenType::Identifier);//变量名
    if (!variable_token)
    {
        setErrorMessage("declaration does not declare anything");
        return std::nullopt;
    }
    ASTNode var_node(ASTNodeType::VarDeclaration, variable_token->token_value, variable_token.value());
    //=
    if (!match(TokenType::Punctuator, "="))
    {
        setErrorMessage("expected '=' after " + variable_token->token_value);
        return std::nullopt;
    }
    //变量类型
    auto type_token = match(TokenType::Identifier);//类型名
    if (!type_token)
    {
        setErrorMessage("declaration does not indicate type");
        return std::nullopt;
    }
    var_node.children.push_back(std::move(ASTNode{ASTNodeType::Identifier, type_token->token_value, type_token.value()}));

    //变量的任务名称名称
    if (!match(TokenType::Punctuator, "("))
    {
        setErrorMessage("expected ‘(’ after " + type_token->token_value);
        return std::nullopt;
    }
    if (!match(TokenType::Punctuator, "\""))
    {
        setErrorMessage("expected ‘\"’ after '('");
        return std::nullopt;
    }
    auto name_token = match(TokenType::Identifier);
    if (name_token)
    {
        var_node.children.push_back(std::move(ASTNode{ASTNodeType::String, name_token->token_value, name_token.value()}));
    }
    else
    {
        setErrorMessage("expected task name after type " + variable_token->token_value);
        return std::nullopt;
    }
    if (!match(TokenType::Punctuator, "\""))
    {
        error_message = "expected ‘\"’ after " + variable_token->token_value;
        return std::nullopt;
    }
    if (!match(TokenType::Punctuator, ")"))
    {
        error_message = "expected ‘)’ after '\"'";
        return std::nullopt;
    }

    return var_node;
}
std::optional<ASTNode> ScriptParserData::parseFunctionDeclaration()
{
    //e.g. function test_func(){}
    auto function_name = match(TokenType::Identifier);//函数名
    if (!function_name)
    {
        setErrorMessage("declaration does not declare anything");
        return std::nullopt;
    }
    ASTNode func_node(ASTNodeType::FuncDeclaration, function_name->token_value, function_name.value());
    //()
    if (!match(TokenType::Punctuator, "(") || !match(TokenType::Punctuator, ")"))
    {
        setErrorMessage("expected '()' after " + function_name->token_value);
        return std::nullopt;
    }
    //函数体
    if(!parseNoWhileExecutant(func_node))
    {
        return std::nullopt;
    }
    return func_node;
}
std::optional<ASTNode> ScriptParserData::parseIfStatement(const Token &token)
{
    //if应该有2～3个子树，分别是判断表达式、执行语句和else执行语句
    ASTNode if_node(ASTNodeType::IfStatement, token);

    //解析条件体
    if (!parseExpression(if_node))
    {
        return std::nullopt;
    }

    //解析执行体
    if (!parseNoWhileExecutant(if_node))
    {
        return std::nullopt;
    }

    //else可以有，也可以没有
    if (match(TokenType::KeyWord, "else"))
    {
        if (!parseNoWhileExecutant(if_node))
        {
            return std::nullopt;
        }
    }
    return if_node;
}
bool ScriptParserData::parseExpression(ASTNode &ast_node)
{
    if (position >= tokens.tokens.size())
    {
        setErrorMessage("excepted expression");
        return false;
    }

    if (auto token = match(TokenType::Punctuator, "("))
    {
        //子表达式
        ASTNode expression_node(ASTNodeType::Expression, token.value());
        if (!parseExpression(expression_node))
        {
            return false;
        }
        ast_node.children.push_back(std::move(expression_node));
        return true;
    }

    while (!match(TokenType::Punctuator, ")"))
    {
        if (auto token = match(TokenType::Punctuator, "("))//嵌套()
        {
            ASTNode expression_node_continue(ASTNodeType::Expression, token.value());
            if (!parseExpression(expression_node_continue))
            {
                return false;
            }
            ast_node.children.push_back(std::move(expression_node_continue));
        }
        else if (!parseExpressionContent(ast_node))
        {
            return false;
        }
    }

    parseContinueAndExpression(ast_node);   //这里再处理一下操作符，连续and合并
    parseContinueOrExpression(ast_node);    //这里再处理一下操作符，连续or合并
    return true;
}
bool ScriptParserData::parseExpressionContent(ASTNode &ast_node)
{
    //表达式()内部
    ASTNode expression_node_continue;
    if (auto and_token = match(TokenType::KeyWord, "and"))//Check for logical AND operator
    {
        expression_node_continue.type = ASTNodeType::AND;
        expression_node_continue.token = and_token.value();
        if (!parseAndExpression(expression_node_continue))//and优先级比or高，需要先全部处理完，再处理or
        {
            return false;
        }
        ast_node.children.push_back(std::move(expression_node_continue));
    }
    else if (auto or_token = match(TokenType::KeyWord, "or"))//Check for logical or operator
    {
        expression_node_continue.type = ASTNodeType::OR;
        expression_node_continue.token = or_token.value();
        ast_node.children.push_back(std::move(expression_node_continue));
    }
    else if (auto not_token = match(TokenType::Punctuator, "!"))//Check for logical not operator
    {
        expression_node_continue.type = ASTNodeType::NOT;
        expression_node_continue.token = not_token.value();
        if (!parseNotExpression(expression_node_continue))
        {
            return false;
        }
        ast_node.children.push_back(std::move(expression_node_continue));
    }
    else
    {
        //标识符
        auto identifier_node = match(TokenType::Identifier);
        if (identifier_node)
        {
            expression_node_continue.type = ASTNodeType::Identifier;
            expression_node_continue.value = identifier_node->token_value;
            expression_node_continue.token = identifier_node.value();
            ast_node.children.push_back(std::move(expression_node_continue));
        }
        else
        {
            error_message = "unexpected token";
            return false;
        }
    }
    return true;
}
bool ScriptParserData::parseAndExpression(ASTNode &ast_node)
{
    if (position >= tokens.tokens.size())
    {
        setErrorMessage("excepted expression");
        return false;
    }
    if (auto token = match(TokenType::Punctuator, "("))
    {
        //子表达式
        ASTNode expression_node(ASTNodeType::Expression, token.value());
        if (!parseExpression(expression_node))
        {
            return false;
        }
        ast_node.children.push_back(std::move(expression_node));
        return true;
    }
    //and后是!
    if (auto punctuator = match(TokenType::Punctuator, "!"))
    {
        ASTNode expression_node(ASTNodeType::NOT, punctuator->token_value, punctuator.value());
        if (!parseNotExpression(expression_node))
        {
            return false;
        }
        ast_node.children.push_back(std::move(expression_node));
        return true;
    }
    //and后是标识符
    auto identifier = match(TokenType::Identifier);
    if (!identifier)
    {
        setErrorMessage("expected identifier after 'and'");
        return false;
    }
    ast_node.children.emplace_back(ASTNodeType::Identifier, identifier->token_value, identifier.value());
    return true;
}
bool ScriptParserData::parseContinueAndExpression(ASTNode &ast_node)
{
    //把连续and，加上前面的表达式，合并成一个and
    if (ast_node.children.empty())
    {
        setErrorMessage("expected expression, expression cannot be empty");
        return false;
    }
    std::vector<ASTNode> new_expression_children;
    ASTNode group_and_node(ASTNodeType::AND);
    for (auto &node: ast_node.children)
    {
        if (ASTNodeType::AND == node.type)
        {
            group_and_node.token = node.token;
            group_and_node.children.insert(group_and_node.children.end(), node.children.begin(), node.children.end());
        }
        else if (!group_and_node.children.empty())
        {
            //这两行代码是将and的前一个节点放到and中
            group_and_node.children.insert(group_and_node.children.begin(), std::move(*(new_expression_children.end() - 1)));
            new_expression_children.erase(new_expression_children.end());

            new_expression_children.push_back(group_and_node);
            group_and_node.children.clear();
            new_expression_children.push_back(std::move(node));
        }
        else
        {
            new_expression_children.push_back(std::move(node));
        }
    }
    //全是and的情况
    if (!group_and_node.children.empty())
    {
        group_and_node.children.insert(group_and_node.children.begin(), std::move(*(new_expression_children.end() - 1)));
        new_expression_children.erase(new_expression_children.end());
        new_expression_children.push_back(group_and_node);
        group_and_node.children.clear();
    }
    ast_node.children = new_expression_children;
    return true;
}
bool ScriptParserData::parseContinueOrExpression(ASTNode &ast_node)
{
    //把连续的or，加上前面的表达式，合并成一个or
    if (ast_node.children.size() < 3)
    {
        //没有逻辑条件的，不处理
        return true;
    }

    std::vector<ASTNode> node_vec;
    Token token;
    bool has_or = false;
    for (auto &node: ast_node.children)
    {
        if (ASTNodeType::OR != node.type)
        {
            node_vec.push_back(std::move(node));
        }
        else
        {
            token = node.token;
            has_or = true;
        }
    }
    if (has_or)
    {
        ASTNode or_node(ASTNodeType::OR, token);
        or_node.children = std::move(node_vec);
        ast_node.children.clear();
        ast_node.children.push_back(std::move(or_node));
    }

    return false;
}
bool ScriptParserData::parseNotExpression(ASTNode &ast_node)
{
    if (position >= tokens.tokens.size())
    {
        setErrorMessage("excepted expression");
        return false;
    }
    if (auto token = match(TokenType::Punctuator, "("))
    {
        //子表达式
        ASTNode expression_node(ASTNodeType::Expression, token.value());
        if (!parseExpression(expression_node))
        {
            return false;
        }
        ast_node.children.push_back(std::move(expression_node));
        return true;
    }
    auto identifier = match(TokenType::Identifier);
    if (!identifier)
    {
        setErrorMessage("expected identifier after '!'");
        return false;
    }
    ast_node.children.emplace_back(ASTNodeType::Identifier, identifier->token_value);
    return true;
}
bool ScriptParserData::parseNoWhileExecutant(ASTNode &ast_node)
{
    if (!match(TokenType::Punctuator, "{"))
    {
        error_message = "missing opening brace";
        return false;
    }
    ASTNode executant_ast_node(ASTNodeType::Root);
    while (!match(TokenType::Punctuator, "}"))
    {
        auto statement_node = parseStatement();
        if (statement_node)
        {
            executant_ast_node.children.push_back(std::move(statement_node.value()));
        }
        else if (ASTNodeType::Break == statement_node->type)
        {
            //if不该有break
            setErrorMessage("break statement not within loop or switch");
            return false;
        }
        else
        {
            return false;
        }
    }
    ast_node.children.push_back(std::move(executant_ast_node));
    return true;
}
bool ScriptParserData::parseNoWhileExecutantDirect(ASTNode &ast_node)
{
    if (!match(TokenType::Punctuator, "{"))
    {
        error_message = "missing opening brace";
        return false;
    }
    while (!match(TokenType::Punctuator, "}"))
    {
        auto statement_node = parseStatement();
        if (statement_node)
        {
            ast_node.children.push_back(std::move(statement_node.value()));
        }
        else if (ASTNodeType::Break == statement_node->type)
        {
            //if不该有break
            setErrorMessage("break statement not within loop or switch");
            return false;
        }
        else
        {
            return false;
        }
    }
    return true;
}
bool ScriptParserData::parseWhileExecutant(ASTNode &ast_node)
{
    if (!match(TokenType::Punctuator, "{"))
    {
        error_message = "missing opening brace";
        return false;
    }
    ASTNode executant_ast_node(ASTNodeType::Root);
    while (!match(TokenType::Punctuator, "}"))
    {
        auto statement_node = parseStatement();
        if (statement_node)
        {
            executant_ast_node.children.push_back(std::move(statement_node.value()));
        }
        else
        {
            return false;
        }
    }
    ast_node.children.push_back(std::move(executant_ast_node));
    return true;
}
std::optional<ASTNode> ScriptParserData::parseRepeatStatement(const Token &token)
{
    ASTNode repeat_node(ASTNodeType::RepeatStatement, token);

    if (!match(TokenType::Punctuator, "("))
    {
        error_message = "missing opening parenthesis";
        return std::nullopt;
    }

    auto repeat_count_token = match(TokenType::Numeric);
    if (!repeat_count_token)
    {
        error_message = "invalid repeat count";
        return std::nullopt;
    }
    repeat_node.value = repeat_count_token->token_value;
    repeat_node.token = repeat_count_token.value();

    if (!match(TokenType::Punctuator, ")"))
    {
        error_message = "missing closing parenthesis";
        return std::nullopt;
    }

    //解析执行体
    if (!parseNoWhileExecutant(repeat_node))
    {
        return std::nullopt;
    }
    return repeat_node;
}
std::optional<ASTNode> ScriptParserData::parseRetryStatement(const Token &token)
{
    ASTNode repeat_node(ASTNodeType::RetryStatement, token);

    if (!match(TokenType::Punctuator, "("))
    {
        error_message = "missing opening parenthesis";
        return std::nullopt;
    }
    auto retry_count_token = match(TokenType::Numeric);
    if (!retry_count_token)
    {
        error_message = "invalid retry count";
        return std::nullopt;
    }
    repeat_node.value = retry_count_token->token_value;
    if (!match(TokenType::Punctuator, ")"))
    {
        error_message = "missing closing parenthesis";
        return std::nullopt;
    }

    //解析执行体
    if (!parseNoWhileExecutant(repeat_node))
    {
        return std::nullopt;
    }
    return repeat_node;
}
std::optional<ASTNode> ScriptParserData::parseWhileLoop(const Token &token)
{
    ASTNode while_node(ASTNodeType::WhileLoop, token);

    //解析while循环条件
    if (!parseExpression(while_node))
    {
        return std::nullopt;
    }
    //解析执行体
    if (!parseWhileExecutant(while_node))
    {
        return std::nullopt;
    }
    return while_node;
}
std::optional<ASTNode> ScriptParserData::parseReactiveStatement(const Token &token)
{
    ASTNode reactive_node(ASTNodeType::ReactiveStatement, token);

    //解析reactive条件
    if (!parseExpression(reactive_node))
    {
        return std::nullopt;
    }

    //解析执行体
    if (!parseNoWhileExecutant(reactive_node))
    {
        return std::nullopt;
    }
    return reactive_node;
}
std::optional<ASTNode> ScriptParserData::parseParallelStatement(const Token &token)
{
    ASTNode parallel_node(ASTNodeType::ParallelStatement, token);

    //解析执行体
    if (!parseNoWhileExecutantDirect(parallel_node))
    {
        return std::nullopt;
    }
    return parallel_node;
}
std::optional<ASTNode> ScriptParserData::parseForcePassStatement(const Token &token)
{
    ASTNode force_pass_node(ASTNodeType::ForcePassStatement, token);
    //解析执行体
    if (!parseNoWhileExecutant(force_pass_node))
    {
        return std::nullopt;
    }
    return force_pass_node;
}
std::optional<ASTNode> ScriptParserData::parseForceFailStatement(const Token &token)
{
    ASTNode force_fail_node(ASTNodeType::ForceFailStatement, token);
    //解析执行体
    if (!parseNoWhileExecutant(force_fail_node))
    {
        return std::nullopt;
    }
    return force_fail_node;
}
std::optional<Token> ScriptParserData::match(TokenType token_type)
{
    if (position >= tokens.tokens.size())
    {
        return std::nullopt;
    }
    if (position < tokens.tokens.size() && tokens.tokens.at(position).type == token_type)
    {
        return tokens.tokens.at(position++);
    }
    return std::nullopt;
}
std::optional<Token> ScriptParserData::match(TokenType token_type, const std::string &value)
{
    if (position >= tokens.tokens.size())
    {
        return std::nullopt;
    }
    Token token = tokens.tokens.at(position);
    if (position < tokens.tokens.size() && token.type == token_type && token.token_value == value)
    {
        return tokens.tokens.at(position++);
    }
    return std::nullopt;
}
void ScriptParserData::setErrorMessage(const std::string &error_massage)
{
    if (error_message.empty())
    {
        error_message = error_massage;
    }
}
}

namespace script
{
ScriptParser::ScriptParser()
    : d(std::make_unique<ScriptParserData>())
{

}
ScriptParser::~ScriptParser() = default;

std::optional<ASTNode> ScriptParser::parse(const Tokens &tokens)
{
    d->tokens = tokens;
    return d->parseStatements();
}
void ScriptParser::getErrorInfo(Token *error_token, std::string *error_msg) const
{
    *error_token = d->tokens.tokens.at(d->position);
    *error_msg = d->error_message;
}

}
